<template>
  <basic-container>
    <el-steps :active="step" finish-status="success" simple style="margin-bottom: 20px">
      <el-step title="设计表单" icon="el-icon-edit"></el-step>
      <el-step title="设计流程" icon="el-icon-upload">
        <template #title>
          设计流程
          <el-tooltip v-show="step == '1'" content="全屏">
            <i class="el-icon-full-screen" @click="handleFullScreen"></i>
          </el-tooltip>
        </template>
      </el-step>
      <el-step title="完成" icon="el-icon-circle-check"></el-step>
    </el-steps>

    <div v-show="step == 0">
      <avue-form style="margin-bottom: 66px" ref="form1" :option="step1.option" v-model="step1.form">
        <template #tip>
          <el-link type="primary" :underline="false" @click="$router.push('/plugin/workflow/design/form')"
            >没有想要的表单？点击去设计</el-link
          >
        </template>
        <template #form>
          <avue-form
            v-if="option && ((option.column && option.column.length > 0) || (option.group && option.group.length > 0))"
            ref="form2"
            v-model="form"
            :option="option"
          ></avue-form>
        </template>
      </avue-form>
    </div>
    <div v-if="step == 1">
      <wf-design
        id="bpmn2"
        ref="bpmn2"
        style="height: calc(100vh - 290px); background: white"
        :options="step2.option"
      ></wf-design>
    </div>
    <div v-if="step == 2">
      <wf-design ref="bpmn3" style="height: calc(100vh - 290px)" :options="step3.option"></wf-design>
    </div>

    <div class="foot-item" :style="{ width: isCollapse ? 'calc(100% - 80px)' : 'calc(100% - 260px)' }">
      <el-button type="primary" size="medium" v-if="step > 0" @click="step--">上一步</el-button>
      <el-button type="success" size="medium" v-if="step < 2" @click="handleNextStep">下一步</el-button>
      <el-button type="success" size="medium" v-if="step == 2" @click="handleSave">保存</el-button>
    </div>
  </basic-container>
</template>

<script>
import { getDetail as getFormByKey } from '@/api/plugin/workflow/form'
import { submit, getDetail } from '@/api/plugin/workflow/model'
import { getList as buttonList } from '@/api/plugin/workflow/button'
import { userList } from '@/api/plugin/workflow/process'

import { fullscreenToggel } from '@/util/util'

export default {
  name: 'design',
  props: ['param'],
  data() {
    const _this = this
    return {
      form: {},
      option: {},
      step: 0,
      step1: {
        form: {},
        option: {
          menuBtn: false,
          group: [
            {
              labelPosition: 'left',
              label: '选择表单',
              icon: 'el-icon-warning-outline',
              arrow: false,
              column: [
                {
                  label: '表单类型',
                  prop: 'formType',
                  type: 'radio',
                  dicData: [
                    {
                      label: '内置表单',
                      value: 1
                    },
                    {
                      label: '外置表单',
                      value: 2
                    },
                    {
                      label: '节点独立表单',
                      value: 3
                    }
                  ],
                  span: 24,
                  value: 1,
                  event: {
                    change: val => {
                      if (!val) return
                      if (val == 1) {
                        this.findObject(this.step1.option.group[0].column, 'exFormKey').display = false
                        this.findObject(this.step1.option.group[1].column, 'column').display = false
                        this.findObject(this.step1.option.group[0].column, 'formKey').display = true
                        this.findObject(this.step1.option.group[0].column, 'tip').display = true
                        this.findObject(this.step1.option.group[1].column, 'form').display = true
                        this.step1.option.group[1].display = true
                      } else if (val == 2) {
                        this.findObject(this.step1.option.group[0].column, 'exFormKey').display = true
                        this.findObject(this.step1.option.group[1].column, 'column').display = true
                        this.findObject(this.step1.option.group[0].column, 'formKey').display = false
                        this.findObject(this.step1.option.group[0].column, 'tip').display = false
                        this.option = {}
                        this.step1.option.group[1].display = true
                      } else if (val == 3) {
                        this.findObject(this.step1.option.group[0].column, 'exFormKey').display = false
                        this.findObject(this.step1.option.group[1].column, 'column').display = false
                        this.findObject(this.step1.option.group[0].column, 'formKey').display = false
                        this.findObject(this.step1.option.group[0].column, 'tip').display = false
                        this.option = {}
                        this.step1.option.group[1].display = false
                      }
                    }
                  }
                },
                {
                  label: '表单key',
                  prop: 'exFormKey',
                  display: false,
                  rules: [{ required: true, message: '请输入外置表单key' }]
                },
                {
                  label: '表单',
                  prop: 'formKey',
                  type: 'select',
                  props: {
                    label: 'name',
                    value: 'formKey'
                  },
                  dicData: [],
                  event: {
                    change: val => {
                      _this.option = { menuBtn: false, readonly: true }
                      if (val) {
                        getFormByKey({ formKey: val })
                          .then(res => {
                            _this.option = {
                              ...eval('(' + res.data.data.content.replace(/this/g, '_this') + ')'),
                              menuBtn: false,
                              readonly: true
                            }
                            _this.findObject(this.step1.option.group[1].column, 'form').display = true
                          })
                          .catch(() => {
                            _this.findObject(this.step1.option.group[1].column, 'form').display = false
                          })
                      } else {
                        _this.findObject(this.step1.option.group[1].column, 'form').display = false
                      }
                    }
                  },
                  rules: [{ required: true, message: '请选择表单' }],
                  display: true,
                  filterable: true
                },
                {
                  labelWidth: 0,
                  prop: 'tip',
                  formslot: true
                }
              ]
            },
            {
              label: '表单预览',
              icon: 'el-icon-view',
              display: true,
              arrow: false,
              column: [
                {
                  prop: 'form',
                  labelWidth: 0,
                  span: 24,
                  formslot: true,
                  display: false
                },
                {
                  prop: 'column',
                  labelWidth: '0',
                  tip: '可用于控制外置表单字段的显隐配置，如果希望自己控制请忽略此字段',
                  tipPlacement: 'top',
                  span: 24,
                  type: 'dynamic',
                  children: {
                    align: 'center',
                    column: [
                      {
                        label: '字段',
                        prop: 'label',
                        rules: [{ required: true, message: '请输入字段名' }]
                      },
                      {
                        label: '属性',
                        prop: 'prop',
                        rules: [{ required: true, message: '请输入属性名' }]
                      },
                      {
                        label: '默认可读',
                        prop: 'readable',
                        type: 'switch',
                        disabled: true,
                        value: true
                      },
                      {
                        label: '默认可写',
                        prop: 'writable',
                        type: 'switch',
                        disabled: true,
                        value: true
                      }
                    ]
                  },
                  display: false
                }
              ]
            }
          ]
        }
      },
      step2: {
        option: {
          config: false,
          mode: 'edit',
          engine: 'flowable',
          toolbar: ['open', 'create', 'fit', 'zoom-in', 'zoom-out', 'undo', 'redo', 'import', 'preview'],
          script: {
            script: {
              enable: false,
              alert:
                '使用之前请先了解脚本会带来的危害，若确定使用请参考文档放开此配置。<br>1、脚本中可以完全访问JVM。<br>2、脚本执行时阻塞许多系统资源。<br>3、脚本执行死循环/占用大量内存等会导致程序崩溃。'
            },
            shell: {
              enable: false,
              alert:
                '使用之前请先了解Shell会带来的危害，若确定使用请参考文档放开此配置。<br>因不确定是否可执行危险命令，如rm -rf *，请充分了解之后再使用。',
              pattern: '(rm|mv|kill|ifconfig|docker|reboot|dd|wget|shutdown|halt|poweroff|init|:(){:|:&};:|^foo^bar)'
            }
          }
        }
      },
      step3: {
        option: {
          config: false,
          mode: 'view',
          simulation: true,
          minimap: true,
          engine: 'flowable'
        }
      },
      process: {},
      fullscreen: false
    }
  },
  mounted() {
    console.log(this.$store)
    this.handler()
    this.language()
    this.getButtonList()
    // this.getUserList()
    this.getUserListV2()
    this.getFormList()

    // let buttons = []
    // if (this.step > 0)
    //   buttons.push({
    //     text: '上一步',
    //     callback: () => this.step--
    //   })
    // if (this.step < 2)
    //   buttons.push({
    //     text: '下一步',
    //     callback: this.handleNextStep
    //   })
    // if (this.step == 2)
    //   buttons.push({
    //     text: '保存',
    //     callback: this.handleSave
    //   })
    // buttons.push({
    //   text: '取消',
    //   type: 'default',
    //   callback: () => {
    //     this.$emit('update:visible', false)
    //   }
    // })
    // this.$emit('update:buttons', buttons)
  },
  methods: {
    handleNextStep() {
      switch (this.step) {
        case 0:
          this.$refs.form1.validate((valid, done) => {
            if (valid) {
              const { formType, formKey, exFormKey, column } = this.step1.form
              if (formType == 1) {
                // 内置表单
                this.process.formKey = formKey
                this.$set(this.step2.option, 'form', this.option)
              } else if (formType == 2) {
                // 外置表单
                this.process.formKey = 'wf_ex_' + exFormKey
                this.$set(this.step2.option, 'exForm', {
                  exFormKey,
                  column
                })
              } else if (formType == 3) {
                // 独立表单
                this.$set(this.step2.option, 'indepForm', {
                  mode: 'indep',
                  list: this.formList
                })
              }
              this.step++
              done()
            }
          })
          break
        case 1:
          if (this.step1.form.formType == 3) {
            // 节点独立表单
            const registry = this.$refs.bpmn2.getElementRegistry().getAll()
            let errorList = []
            registry.forEach(ele => {
              this.validateIndepFormOption(ele, errorList)
            })
            if (errorList.length > 0) {
              errorList = new Set(errorList)
              let message = ''
              errorList.forEach(err => {
                const { businessObject } = err
                const { id, name } = businessObject
                message += `<p>${name || id} 节点未正确配置表单</p>`
              })
              this.$message({
                type: 'error',
                dangerouslyUseHTMLString: true,
                message
              })
              return
            }
          }
          this.$refs.bpmn2.getData('xml').then(data => {
            console.log(this)
            this.$set(this.step2.option, 'xml', data)
            this.$set(this.step3.option, 'xml', data)
            this.process.xml = data
            this.step++
          })
          break
      }
    },
    handleSave() {
      const registry = this.$refs.bpmn3.getElementRegistry().getAll()
      const { businessObject } = registry[0]
      const { id, name, documentation } = businessObject
      const description = documentation && documentation.length > 0 ? documentation[0].text : null

      const { formType } = this.step1.form
      if (formType == 3) {
        // 节点独立表单
        const startEvent = registry.find(r => r.type == 'bpmn:StartEvent')
        if (startEvent) {
          const indepFormKey = startEvent.businessObject.extensionElements.values.find(
            v => v.$type == 'flowable:indepFormKey'
          )
          if (indepFormKey) this.process.formKey = 'wf_indep_' + indepFormKey.value
        }
      }

      const params = {
        ...this.process,
        modelKey: id,
        name,
        description
      }

      if (this.process.id) {
        this.$confirm('是否将此模型保存为新版本？这意味着可以返回到以前的版本。', '提示', {
          distinguishCancelAndClose: true,
          confirmButtonText: '否',
          cancelButtonText: '是',
          type: 'warning'
        })
          .then(() => {
            params.newVersion = false

            submit(params).then(() => {
              this.$message.success('操作成功')
              this.$emit('update:visible', false)
              this.$emit('refresh')
            })
          })
          .catch(action => {
            if (action === 'cancel') {
              params.newVersion = true

              submit(params).then(() => {
                this.$message.success('操作成功')
                this.$emit('update:visible', false)
                this.$emit('refresh')
              })
            }
          })
      } else {
        submit(params).then(() => {
          this.$message.success('操作成功')
          this.$emit('update:visible', false)
          this.$emit('refresh')
        })
      }
    },
    validateIndepFormOption(element, errorList) {
      const { type, businessObject, children } = element
      const indepFormKey = 'flowable:IndepFormKey'
      const indepFormSummary = 'flowable:IndepFormSummary'
      if ('bpmn:StartEvent' == type) {
        const extensionElements = businessObject.extensionElements
        if (extensionElements && extensionElements.values && extensionElements.values.length > 0) {
          const summary = extensionElements.values.find(v => v.$type == indepFormSummary)
          if (!extensionElements.values.find(v => v.$type == indepFormKey) && (!summary || summary == '0'))
            errorList.push(element)
        } else errorList.push(element)
      } else if ('bpmn:UserTask' == type) {
        const summary = businessObject['indepFormSummary']
        if (!businessObject['indepFormKey'] && (!summary || summary == '0')) errorList.push(element)
      } else if ('bpmn:SubProcess' == type) {
        children.forEach(ele => this.validateIndepFormOption(ele, errorList))
      }
    },
    getButtonList() {
      buttonList(1, 99, { status: 1 }).then(res => {
        const list = res.data.data.records.map(l => {
          return {
            label: l.name,
            prop: l.buttonKey,
            display: l.display
          }
        })
        this.$set(this.step2.option, 'button', list)
      })
    },
    getFormList() {
      this.$axios.get('/api/blade-workflow/design/form/list?size=-1&status=1').then(res => {
        this.formList = res.data.data.records
        this.findObject(this.step1.option.group, 'formKey').dicData = this.formList
      })
    },
    getUserList() {
      const userConfig = {
        leftColumns: [
          {
            title: '姓名',
            dataIndex: 'realName',
            align: 'center'
          },
          {
            title: '部门',
            dataIndex: 'deptName',
            align: 'center'
          },
          {
            title: '职位',
            dataIndex: 'postName',
            align: 'center'
          }
        ],
        rightColumns: [
          {
            title: '姓名',
            dataIndex: 'realName',
            align: 'center'
          }
        ],
        filterKey: 'realName'
      }
      userList(1, 99, {}).then(res => {
        userConfig.data = res.data.data.records.map(r => {
          return {
            key: r.id,
            realName: r.realName,
            deptName: r.deptName
          }
        })
        this.$set(this.step2.option, 'user', userConfig)
      })
    },
    getUserListV2() {
      this.$set(this.step2.option, 'user', {
        version: 'v2',
        userUrl: '/api/blade-user/search/user',
        roleUrl: '/api/blade-system/search/role',
        deptUrl: '/api/blade-system/search/dept',
        postUrl: '/api/blade-system/search/post',
        customUrl: '/api/blade-workflow/design/condition/list'
      })
    },
    handleFullScreen() {
      fullscreenToggel()
      this.$store.commit('SET_COLLAPSE')
    },
    handler() {
      const val = this.param
      if (!val || val == 0) return
      getDetail(val).then(res => {
        this.process = res.data.data
        const { formKey, xml, exForm } = this.process
        this.$set(this.step2.option, 'xml', xml)
        this.$set(this.step2.option, 'process', this.process)
        if (formKey.startsWith('wf_ex_')) {
          // 外置表单
          const column = []
          exForm.forEach(ex => {
            column.push({
              label: ex.name,
              prop: ex.id,
              readable: true,
              writable: true
            })
          })
          this.$set(this.step1.form, 'column', column)
          this.$set(this.step1.form, 'formType', 2)
          this.$set(this.step1.form, 'exFormKey', formKey.substring(6))
        } else if (formKey.startsWith('wf_indep_')) {
          this.$set(this.step1.form, 'formType', 3)
        } else {
          this.$set(this.step1.form, 'formKey', formKey)
        }
      })
    },
    language() {
      const option = {
        lang: this.param
      }
      if (this.$refs.bpmn2) {
        this.$refs.bpmn2.getData('xml', false, false).then(data => {
          option.xml = data
          this.$set(this.step2, 'option', {
            ...this.step2.option,
            ...option
          })
        })
      } else
        this.$set(this.step2, 'option', {
          ...this.step2.option,
          ...option
        })
    }
  }
}
</script>
<style lang="scss">
.wf-design {
  .avue-group__title {
    margin-top: 8px;
  }
}
</style>
<style scoped lang="scss">
.foot-item {
  position: fixed;
  bottom: 0;
  margin-left: -20px;
  // right: 0;
  z-index: 101;
  height: 66px;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  -webkit-transition: 0.3s;
  transition: 0.3s;
  -webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>
